home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / bignums / realconst.sml < prev   
Encoding:
Text File  |  1993-01-27  |  7.2 KB  |  226 lines

  1. (* Copyright 1989 by AT&T Bell Laboratories *)
  2. (*
  3. RealConst: generate ML real constants.
  4. RealConst uses long multiplication to find the correct bit pattern for
  5. the real.  This method is slow, but accurate, and works to any precision,
  6. which means that floats can be cross-compiled correctly.
  7.  
  8. The function emitreal should take (int * bool array * int) which represents
  9. a real value as (sign * fraction * exponent).
  10. The sign is 0 if the real is positive, 1 if negative.
  11. The fraction is a boolean array representing the bits; note that the most
  12. significant bit is in position 0.
  13. The exponent is the binary exponent of the normalized fraction.
  14. "Normalized" here means a number between 0 and 1.
  15.  
  16. The algorithm works inefficient on forms like 10000000.0; forms like 1E7 (with
  17. no bogus zeros) are better.  Also inefficient on forms like 0E23 or 1E~212.
  18. *)
  19.  
  20. signature PRIMREAL = sig
  21. val significant : int
  22. val minexp : int
  23. val maxexp : int
  24. val transreal : (int * (int*int->int) * int) -> string
  25. end
  26.  
  27. signature REALCONST = sig
  28. exception BadReal of string
  29. val realconst : string -> string
  30. end
  31.  
  32. functor RealConst(P : PRIMREAL) : REALCONST =
  33. struct
  34.  
  35. open P
  36.  
  37. exception BadReal of string
  38.  
  39. (* Use more than the required precision, then round at the end.
  40.    This criterion works well enough for the 53 bits required by
  41.    Vax G format and IEEE double format, but has not been tested with other
  42.    values of significant. *)
  43.  
  44. fun log2 0 = 1 | log2 i = 1+log2(i div 2)
  45. val precision = significant + log2(maxexp-minexp) + 3
  46.  
  47. (* A float is a WHOLE "fraction" and an exponent base TWO. *)
  48. type float = {frac : Bigint.bigint, exp : int}
  49.  
  50. val bigint = Bigint.bigint
  51. val plus = Bigint.+
  52. val times = Bigint.*
  53. infix plus times
  54.  
  55. (* Take a bigint and return a function that will represent the
  56.    fraction.  The function is called with two integers (start,width), and returns
  57.    an integer represented by the bits from start to start+width-1.
  58.    The high (1/2) bit is in position 0.  Assumes that
  59.    the bigint is positive.  This will work if the bigint is smaller than
  60.    the array or vice versa;  however, the number will be truncated, not
  61.    rounded. *)
  62. exception Bits
  63. fun makebits frac (start,width) =
  64.     let val s = Bigint.size frac
  65.     fun onebit b = Bigint.getbit(frac,s-1-b)
  66.     fun b true = 1
  67.           | b false = 0
  68.     fun f 0 = b (onebit start)
  69.           | f i = b (onebit(start+i)) + 2 * f(i-1)
  70.     in if start < 0 orelse width < 0
  71.           then raise Bits
  72.           else f (width-1)
  73.    end
  74.  
  75. (* round a float to n significant digits *)
  76. local val one = bigint 1 in
  77. fun round (float as {frac=f,exp=e},n) =
  78.     let val shift = Bigint.size f + 1 - n
  79.     in
  80.     if shift <= 0 then float
  81.     else {frac = if Bigint.getbit(f,shift-1)
  82.              then Bigint.>>(f, shift) plus one
  83.              else Bigint.>>(f, shift),
  84.           exp = e + shift}
  85.     end
  86. end
  87.  
  88. (* maketenth:  create the float of one tenth, to any number of significant
  89.    digits, with no rounding on the last digit. *)
  90. local val zero = bigint 0 and one = bigint 1 and two = bigint 2 in
  91. fun maketenth 1 = {frac=one,exp= ~4}
  92.   | maketenth n =
  93.     let val {frac,exp} = maketenth(n-1)
  94.     val rec tenthbit = fn 0 => zero | 1 => one
  95.                 | 2 => one | 3 => zero | n => tenthbit(n mod 4)
  96.     val f = (frac times two) plus tenthbit n
  97.     val e = exp - 1
  98.     in
  99.     {frac=f,exp=e}
  100.     end
  101. end
  102.  
  103. (* float values ten and one tenth, to the correct precision. *)
  104. val ten = {frac=bigint 5, exp = 1}
  105. val tenth = round(maketenth(precision+1),precision)
  106.  
  107. (* Multiplies two floats together to the correct precision *)
  108. fun mult {frac=f1,exp=e1} {frac=f2,exp=e2} =
  109.     let val f = f1 times f2
  110.     val e : int = e1 + e2
  111.         (* shouldn't need the type constraint, our comp bug *)
  112.     in
  113.     round({frac=f,exp=e},precision)
  114.     end
  115.  
  116. (* Create a dynamic array of powers of ten *)
  117. structure DFA = Dynamic(struct open Array
  118.                    type float = {frac : Bigint.bigint, exp : int}
  119.                    type elem = unit->float
  120.                    type array = elem array
  121.                end)
  122. local open Array List DFA
  123.       infix 9 sub
  124.       exception Unknown
  125.       fun makelem e = (fn () => e)
  126.       val one = {frac=bigint 1,exp=0}
  127. in
  128.     val pos10 = array(fn () => raise Unknown)    (* 10^2^n *)
  129.     val _ = update(pos10,0,makelem ten)
  130.     val neg10 = array(fn () => raise Unknown)    (* 10^~2^n *)
  131.     val _ = update(neg10,0,makelem tenth)
  132.     fun access(arr,n) = (arr sub n) ()
  133.             handle Unknown => let val last = access(arr,n-1)
  134.                            val new = mult last last
  135.                        in  update(arr,n,makelem new);
  136.                            new
  137.                        end
  138.  
  139.     fun pow10_2 0 = one
  140.       | pow10_2 n = if n > 0 then access(pos10,n-1) else access(neg10,~n-1)
  141.     fun raisepower(f,0) = f
  142.       | raisepower(f,e) =
  143.         let val sign = if e<0 then ~1 else 1
  144.         fun power(f,p) = mult f (pow10_2(sign*p))
  145.         fun raisep(f,0,_) = f
  146.           | raisep(f,e,p) =
  147.             if Bits.andb(e,1) = 1 then raisep(power(f,p),Bits.rshift(e,1),p+1)
  148.             else raisep(f,Bits.rshift(e,1),p+1)
  149.         in  raisep(f,abs e,1)
  150.         end
  151. end
  152.  
  153. (* Takes a string list of the form {digit*.[digit*]}, and returns a bigint and
  154.    the exponent base 10.  Requires that the list contain a decimal point and
  155.    no trailing zeros (useless zeros after the decimal point). *)
  156. local val ten = bigint 10 and zero = bigint 0 in
  157. fun reducefrac f =
  158.     let fun getexp nil = 0
  159.       | getexp ("."::_) = 0
  160.       | getexp (_::tl) = getexp tl - 1
  161.     fun getwhole nil = zero
  162.       | getwhole ("."::tl) = getwhole tl
  163.       | getwhole ("0"::tl) = ten times getwhole tl
  164.       | getwhole (n::tl) = bigint(ord n - ord "0") plus (ten times getwhole tl)
  165.     val backwards = rev f
  166.     val whole = getwhole backwards
  167.     val exp = getexp backwards
  168.     in
  169.     (whole,exp)
  170.     end
  171. end
  172.  
  173. (* Takes a legal ML float string and returns an (int * bigint * int)
  174.    which is the sign, whole "fraction", and power of ten exponent *)
  175. fun getparts s =
  176.     let datatype trailing = SIGNIFICANT | TRAILING
  177.     (* separate the fraction from the exponent, adding a decimal point if
  178.        there is none and eliminating trailing zeros *)
  179.     fun separate (nil,s) = (nil,nil,s)
  180.       | separate ("E"::tl,SIGNIFICANT) = (["."],tl,SIGNIFICANT)
  181.       | separate ("E"::tl,TRAILING) = (nil,tl,TRAILING)
  182.       | separate ("0"::tl,s) =
  183.         let val (r,e,s) = separate(tl,s)
  184.         in  case s of TRAILING => (r,e,TRAILING)
  185.                 | SIGNIFICANT => ("0"::r,e,SIGNIFICANT)
  186.         end
  187.       | separate ("."::tl,_) =
  188.         let val (r,e,_) = separate(tl,TRAILING)
  189.         in  ("."::r,e,SIGNIFICANT)
  190.         end
  191.       | separate (hd::tl,s) =
  192.         let val (r,e,_) = separate(tl,s)
  193.         in  (hd::r,e,SIGNIFICANT)
  194.         end
  195.     val (unsigned,sign) = case explode s of "~"::more => (more,1)
  196.                           | other => (other,0)
  197.     val (frac_s,exp_s,_) = separate(unsigned,SIGNIFICANT)
  198.     fun atoi strlist =
  199.         let    val numlist = map (fn n => ord n - ord "0") strlist
  200.         in  List.revfold (fn (a:int,b) => b*10 + a) numlist 0
  201.         end
  202.     val exp10 = (case exp_s of nil => 0
  203.                  | "~"::more => ~(atoi more)
  204.                  | other => atoi other)
  205.             handle Overflow => raise BadReal s
  206.     val (frac,exp) = reducefrac frac_s
  207.     in 
  208.     (sign,frac,exp10 + exp)
  209.     end
  210.  
  211. fun realconst f = 
  212.     let val (sign,frac10,exp10) = getparts f
  213.     val float = raisepower(round({frac=frac10,exp=0},precision),exp10)
  214.     val (newf as {frac,exp}) = round(float,significant+1)
  215.     val size = Bigint.size frac
  216.     val bits = makebits frac
  217.     val exp = exp+size
  218.     in transreal(
  219.     case size 
  220.      of 0 => (0,bits,0)
  221.       | _ => if exp<minexp orelse exp>maxexp then raise BadReal f
  222.           else (sign,bits,exp))
  223.     end
  224.  
  225. end (* functor RealConst *)
  226.